import "../../lib/ramda.js";

const PIECE_SIDE_MAP = [0, 2, 1]
const PIECE_WAYS = [0.0, -1.0, 1.0]
const LOC_WAY_TABLE = [
    [0,15,0,1,0,0,0,16],
    [1,16,0,2,1,1,15,17],
    [2,17,1,3,2,2,16,18],
    [3,18,2,4,3,3,17,19],
    [4,19,3,5,4,4,18,20],
    [5,20,4,6,5,5,19,21],
    [6,21,5,7,6,6,20,22],
    [7,22,6,8,7,7,21,23],
    [8,23,7,9,8,8,22,24],
    [9,24,8,10,9,9,23,25],
    [10,25,9,11,10,10,24,26],
    [11,26,10,12,11,11,25,27],
    [12,27,11,13,12,12,26,28],
    [13,28,12,14,13,13,27,29],
    [14,29,13,14,14,14,28,14],
    [0,30,15,16,15,1,15,31],
    [1,31,15,17,0,2,30,32],
    [2,32,16,18,1,3,31,33],
    [3,33,17,19,2,4,32,34],
    [4,34,18,20,3,5,33,35],
    [5,35,19,21,4,6,34,36],
    [6,36,20,22,5,7,35,37],
    [7,37,21,23,6,8,36,38],
    [8,38,22,24,7,9,37,39],
    [9,39,23,25,8,10,38,40],
    [10,40,24,26,9,11,39,41],
    [11,41,25,27,10,12,40,42],
    [12,42,26,28,11,13,41,43],
    [13,43,27,29,12,14,42,44],
    [14,44,28,29,13,29,43,29],
    [15,45,30,31,30,16,30,46],
    [16,46,30,32,15,17,45,47],
    [17,47,31,33,16,18,46,48],
    [18,48,32,34,17,19,47,49],
    [19,49,33,35,18,20,48,50],
    [20,50,34,36,19,21,49,51],
    [21,51,35,37,20,22,50,52],
    [22,52,36,38,21,23,51,53],
    [23,53,37,39,22,24,52,54],
    [24,54,38,40,23,25,53,55],
    [25,55,39,41,24,26,54,56],
    [26,56,40,42,25,27,55,57],
    [27,57,41,43,26,28,56,58],
    [28,58,42,44,27,29,57,59],
    [29,59,43,44,28,44,58,44],
    [30,60,45,46,45,31,45,61],
    [31,61,45,47,30,32,60,62],
    [32,62,46,48,31,33,61,63],
    [33,63,47,49,32,34,62,64],
    [34,64,48,50,33,35,63,65],
    [35,65,49,51,34,36,64,66],
    [36,66,50,52,35,37,65,67],
    [37,67,51,53,36,38,66,68],
    [38,68,52,54,37,39,67,69],
    [39,69,53,55,38,40,68,70],
    [40,70,54,56,39,41,69,71],
    [41,71,55,57,40,42,70,72],
    [42,72,56,58,41,43,71,73],
    [43,73,57,59,42,44,72,74],
    [44,74,58,59,43,59,73,59],
    [45,75,60,61,60,46,60,76],
    [46,76,60,62,45,47,75,77],
    [47,77,61,63,46,48,76,78],
    [48,78,62,64,47,49,77,79],
    [49,79,63,65,48,50,78,80],
    [50,80,64,66,49,51,79,81],
    [51,81,65,67,50,52,80,82],
    [52,82,66,68,51,53,81,83],
    [53,83,67,69,52,54,82,84],
    [54,84,68,70,53,55,83,85],
    [55,85,69,71,54,56,84,86],
    [56,86,70,72,55,57,85,87],
    [57,87,71,73,56,58,86,88],
    [58,88,72,74,57,59,87,89],
    [59,89,73,74,58,74,88,74],
    [60,90,75,76,75,61,75,91],
    [61,91,75,77,60,62,90,92],
    [62,92,76,78,61,63,91,93],
    [63,93,77,79,62,64,92,94],
    [64,94,78,80,63,65,93,95],
    [65,95,79,81,64,66,94,96],
    [66,96,80,82,65,67,95,97],
    [67,97,81,83,66,68,96,98],
    [68,98,82,84,67,69,97,99],
    [69,99,83,85,68,70,98,100],
    [70,100,84,86,69,71,99,101],
    [71,101,85,87,70,72,100,102],
    [72,102,86,88,71,73,101,103],
    [73,103,87,89,72,74,102,104],
    [74,104,88,89,73,89,103,89],
    [75,105,90,91,90,76,90,106],
    [76,106,90,92,75,77,105,107],
    [77,107,91,93,76,78,106,108],
    [78,108,92,94,77,79,107,109],
    [79,109,93,95,78,80,108,110],
    [80,110,94,96,79,81,109,111],
    [81,111,95,97,80,82,110,112],
    [82,112,96,98,81,83,111,113],
    [83,113,97,99,82,84,112,114],
    [84,114,98,100,83,85,113,115],
    [85,115,99,101,84,86,114,116],
    [86,116,100,102,85,87,115,117],
    [87,117,101,103,86,88,116,118],
    [88,118,102,104,87,89,117,119],
    [89,119,103,104,88,104,118,104],
    [90,120,105,106,105,91,105,121],
    [91,121,105,107,90,92,120,122],
    [92,122,106,108,91,93,121,123],
    [93,123,107,109,92,94,122,124],
    [94,124,108,110,93,95,123,125],
    [95,125,109,111,94,96,124,126],
    [96,126,110,112,95,97,125,127],
    [97,127,111,113,96,98,126,128],
    [98,128,112,114,97,99,127,129],
    [99,129,113,115,98,100,128,130],
    [100,130,114,116,99,101,129,131],
    [101,131,115,117,100,102,130,132],
    [102,132,116,118,101,103,131,133],
    [103,133,117,119,102,104,132,134],
    [104,134,118,119,103,119,133,119],
    [105,135,120,121,120,106,120,136],
    [106,136,120,122,105,107,135,137],
    [107,137,121,123,106,108,136,138],
    [108,138,122,124,107,109,137,139],
    [109,139,123,125,108,110,138,140],
    [110,140,124,126,109,111,139,141],
    [111,141,125,127,110,112,140,142],
    [112,142,126,128,111,113,141,143],
    [113,143,127,129,112,114,142,144],
    [114,144,128,130,113,115,143,145],
    [115,145,129,131,114,116,144,146],
    [116,146,130,132,115,117,145,147],
    [117,147,131,133,116,118,146,148],
    [118,148,132,134,117,119,147,149],
    [119,149,133,134,118,134,148,134],
    [120,150,135,136,135,121,135,151],
    [121,151,135,137,120,122,150,152],
    [122,152,136,138,121,123,151,153],
    [123,153,137,139,122,124,152,154],
    [124,154,138,140,123,125,153,155],
    [125,155,139,141,124,126,154,156],
    [126,156,140,142,125,127,155,157],
    [127,157,141,143,126,128,156,158],
    [128,158,142,144,127,129,157,159],
    [129,159,143,145,128,130,158,160],
    [130,160,144,146,129,131,159,161],
    [131,161,145,147,130,132,160,162],
    [132,162,146,148,131,133,161,163],
    [133,163,147,149,132,134,162,164],
    [134,164,148,149,133,149,163,149],
    [135,165,150,151,150,136,150,166],
    [136,166,150,152,135,137,165,167],
    [137,167,151,153,136,138,166,168],
    [138,168,152,154,137,139,167,169],
    [139,169,153,155,138,140,168,170],
    [140,170,154,156,139,141,169,171],
    [141,171,155,157,140,142,170,172],
    [142,172,156,158,141,143,171,173],
    [143,173,157,159,142,144,172,174],
    [144,174,158,160,143,145,173,175],
    [145,175,159,161,144,146,174,176],
    [146,176,160,162,145,147,175,177],
    [147,177,161,163,146,148,176,178],
    [148,178,162,164,147,149,177,179],
    [149,179,163,164,148,164,178,164],
    [150,180,165,166,165,151,165,181],
    [151,181,165,167,150,152,180,182],
    [152,182,166,168,151,153,181,183],
    [153,183,167,169,152,154,182,184],
    [154,184,168,170,153,155,183,185],
    [155,185,169,171,154,156,184,186],
    [156,186,170,172,155,157,185,187],
    [157,187,171,173,156,158,186,188],
    [158,188,172,174,157,159,187,189],
    [159,189,173,175,158,160,188,190],
    [160,190,174,176,159,161,189,191],
    [161,191,175,177,160,162,190,192],
    [162,192,176,178,161,163,191,193],
    [163,193,177,179,162,164,192,194],
    [164,194,178,179,163,179,193,179],
    [165,195,180,181,180,166,180,196],
    [166,196,180,182,165,167,195,197],
    [167,197,181,183,166,168,196,198],
    [168,198,182,184,167,169,197,199],
    [169,199,183,185,168,170,198,200],
    [170,200,184,186,169,171,199,201],
    [171,201,185,187,170,172,200,202],
    [172,202,186,188,171,173,201,203],
    [173,203,187,189,172,174,202,204],
    [174,204,188,190,173,175,203,205],
    [175,205,189,191,174,176,204,206],
    [176,206,190,192,175,177,205,207],
    [177,207,191,193,176,178,206,208],
    [178,208,192,194,177,179,207,209],
    [179,209,193,194,178,194,208,194],
    [180,210,195,196,195,181,195,211],
    [181,211,195,197,180,182,210,212],
    [182,212,196,198,181,183,211,213],
    [183,213,197,199,182,184,212,214],
    [184,214,198,200,183,185,213,215],
    [185,215,199,201,184,186,214,216],
    [186,216,200,202,185,187,215,217],
    [187,217,201,203,186,188,216,218],
    [188,218,202,204,187,189,217,219],
    [189,219,203,205,188,190,218,220],
    [190,220,204,206,189,191,219,221],
    [191,221,205,207,190,192,220,222],
    [192,222,206,208,191,193,221,223],
    [193,223,207,209,192,194,222,224],
    [194,224,208,209,193,209,223,209],
    [195,210,210,211,210,196,210,210],
    [196,211,210,212,195,197,211,211],
    [197,212,211,213,196,198,212,212],
    [198,213,212,214,197,199,213,213],
    [199,214,213,215,198,200,214,214],
    [200,215,214,216,199,201,215,215],
    [201,216,215,217,200,202,216,216],
    [202,217,216,218,201,203,217,217],
    [203,218,217,219,202,204,218,218],
    [204,219,218,220,203,205,219,219],
    [205,220,219,221,204,206,220,220],
    [206,221,220,222,205,207,221,221],
    [207,222,221,223,206,208,222,222],
    [208,223,222,224,207,209,223,223],
    [209,224,223,224,208,224,224,224],
]
const LOC_WAY_MASKS = [
    [0,1,0,1,0,0,0,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,1,0,0,1,1],
    [0,1,1,0,0,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,1,0,1,0,1,0,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,1,1,1,1,1],
    [1,1,1,0,1,0,1,0],
    [1,0,0,1,0,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,1,1,1,0,0],
    [1,0,1,0,1,0,0,0],
]

const _ = {
    PIECE_EMPTY: 0,
    PIECE_BLACK: 1,
    PIECE_WHITE: 2,
    BOARD_SIZE: 15,
    BOARD_LEN: 225,
    LOC_INVALID: -1,
    loc_in_board(loc) {
        return ((loc >= 0) && (loc < _.BOARD_LEN))
    },
    piece_side(p){
        return PIECE_SIDE_MAP[p]
    },
    piece_way(p){
        return PIECE_WAYS[p]
    },
    piece_to_str(p){
        return ((p == _.PIECE_EMPTY) ? '-' : ((p == _.PIECE_BLACK) ? 'b' : 'w'))
    },
    piece_from_str(str){
        return ((str == '-') ? _.PIECE_EMPTY : ((str == 'b') ? _.PIECE_BLACK : _.PIECE_WHITE))
    },
    arr_from_str(str){
        const arr = new Int8Array(_.BOARD_LEN)
        let fill_i = 0
        const units = str.split('|')
        for (const part of units) {
            const p = _.piece_from_str(part[0])
            const n = Number(part.slice(1))
            arr.fill(p, fill_i, fill_i+n)
            fill_i += n
        }
        return arr
    },
    arr_to_str(arr){
        const units = []
        let last = arr[0]
        let n_rept = 0
        for (const i in arr) {
            const p = arr[i]
            if (p == last) {
                n_rept += 1
            } else {
                units.push(`${_.piece_to_str(last)}${n_rept}`)
                last = arr[i]
                n_rept = 1
            }
        }
        units.push(`${_.piece_to_str(last)}${n_rept}`)
        return units.join('|')
    },
}

class Board {
    constructor(_from=undefined) {
        this._arr = new Int8Array(R.is(String,_from) ? _.arr_from_str(_from) : (R.is(Board,_from) ? _from._data() : _.BOARD_LEN))
        this._count_nums = new Uint8Array(3)
    }
    _data(){
        return this._arr
    }
    reset(_from=undefined) {
        if (R.is(Int8Array, _from)) {
            this._arr.set(_from)
        } else if (R.is(Board, _from)) {
            this._arr.set(_from._arr)
        } else {
            this._arr.fill(_.PIECE_EMPTY)
        }
        return this
    }
    to_str() {
        return _.arr_to_str(this._arr)
    }
    _n_count(nums) {
        nums[_.PIECE_EMPTY] = 0
        nums[_.PIECE_BLACK] = 0
        nums[_.PIECE_WHITE] = 0
        for (const p of this._arr) {
            nums[p] += 1
        }
        return nums
    }
    n_black() {
        return (this._n_count(this._count_nums))[_.PIECE_BLACK]
    }
    n_white() {
        return (this._n_count(this._count_nums))[_.PIECE_WHITE]
    }
    n_piece() {
        const nums = this._n_count(this._count_nums)
        return nums[_.PIECE_BLACK] + nums[_.PIECE_WHITE]
    }
    see(loc) {
        return this._arr[loc]
    }
    foreach(fn, _init=undefined){
        for (const loc of R.range(0,_.BOARD_LEN)) {
            _init = fn(loc, this._arr[loc], _init)
        }
        return _init
    }
    _set(loc, p) {
        this._arr[loc] = p
        return this
    }
    moves() {
        return R.range(0,_.BOARD_LEN).filter((loc)=>{return this._arr[loc] == _.PIECE_EMPTY})
    }
    can_down(loc) {
        return this._arr[loc] == _.PIECE_EMPTY
    }
    down(loc, p, _can_down=false) {
        if (_can_down || this.can_down(loc)) {
            this._flip(loc, p)
            return this._set(loc, p)
        }
        return false
    }
    _flip(loc, pcur) {
        const side = _.piece_side(pcur)
        const arr = this._arr
        function on_way(lt, i) {
            const loc = lt[i]
            const p = arr[loc]
            if (((LOC_WAY_MASKS[loc][i] * side) & (p & side)) == _.PIECE_EMPTY) {
                return p & pcur
            }
            if (on_way(LOC_WAY_TABLE[loc], i)) {
                arr[loc] = pcur
                return true
            }
            return false
        }
        const center = LOC_WAY_TABLE[loc]
        for (const i_lt in center) {
            on_way(center, i_lt)
        }
    }
}

class Record {
    constructor(step, loc, pcur) {
        this._step = step
        this._loc = loc
        this._pcur = pcur
    }
    step() {return this._step}
    loc() {return this._loc}
    pcur() {return this._pcur}
}

class State {
    constructor(_from=undefined) {
        this._board = new Board()
        this.reset(_from)
    }

    reset(_from=undefined) {
        if (R.is(State,_from)) {
            this._board.reset(_from._board)
            this._pcur = _from._pcur
            this._end_piece = _from._end_piece
            this._record_top = _from._record_top
        } else {
            this._board.reset()
            this._pcur = _.PIECE_BLACK
            this._end_piece = _.PIECE_EMPTY
            this._record_top = new Record(0, _.LOC_INVALID, _.PIECE_EMPTY)
        }
        return this
    }

    pcur(){
        return this._pcur
    }

    board() {
        return this._board
    }

    has_over() {
        return (this._end_piece != _.PIECE_EMPTY)
    }

    end_piece() {
        return this._end_piece
    }

    record_top() {
        return this._record_top
    }

    can_down(loc) {
        return ((!this.has_over()) && this._board.can_down(loc))
    }

    down(loc) {
        if (this.can_down(loc) && this._board.down(loc, this._pcur, true)) {
            const n_black = this._board.n_black()
            const n_white = this._board.n_white()
            const n_piece = n_black + n_white;
            if (n_piece >= _.BOARD_LEN) {
                this._end_piece = (n_black > n_white) ? _.PIECE_BLACK : ((n_white > n_black) ? _.PIECE_WHITE : _.PIECE_EMPTY-1)
            } else if (n_black > 1 && n_white < 1) {
                this._end_piece = _.PIECE_BLACK
            } else if (n_white > 1 && n_black < 1) {
                this._end_piece = _.PIECE_WHITE
            }
            this._record_top = new Record(n_piece, loc, this._pcur)
            this._pcur = _.piece_side(this._pcur)
            return true
        }
        return false
    }

    random(min_np, max_np) {
        this.reset()
        let np = Math.floor(Math.random() * (1+max_np-min_np)) + min_np
        while ((np > 0) && (! this.has_over())) {
            const moves = this._board.moves()
            for (const loc of R.range(0,_.BOARD_LEN)) {
                const is_can_move = this._board.can_down(loc)
                if (is_can_move) {
                    if (moves.indexOf(loc) < 0) {
                        console.log(`rg-fail can move but not in moves pcur:${this._pcur} loc:${loc} moves:${moves}`)
                        this.reset()
                        return null
                    }
                } else if (moves.indexOf(loc) >= 0) {
                    console.log(`rg-fail can't move but in moves pcur:${this._pcur} loc:${loc} moves:${moves}`)
                    this.reset()
                    return null
                }
            }
            if (moves.length > 0) {
                const loc = moves[Math.floor(Math.random() * moves.length)]
                this.down(loc)
                np -= 1
            }
        }
        return this
    }
}
function random_state(min_np, max_np) {
    const state = new State()
    state.random(min_np, max_np)
    return state
}

export default {
    ..._,
    Board, Record, State, random_state,
}
